use serde::Serialize;

use crate::{error::AppErr, global::APP, serialport::{cmd, proto::Frame, BodyDecode}, utils::BitSet};




pub fn exec(frame: Frame) -> Result<(), AppErr> {
    let cmd = frame.cmd();
    match cmd {
        cmd::STATUS => on_status(frame),
        _ => Err(AppErr::Static("unknown cmd")),
    }
}

struct Status {
    version: u16,
    water_temp: i16,
    steam_temp: i16,
    sensor: u16,
    analog: u16,
    ctrl_flag: u16,
}

impl<'de> BodyDecode<'de> for Status {

    fn decode(buf_ref: &mut &'de [u8]) -> Option<Self>
        where
            Self: Sized {
        let version = u16::decode(buf_ref)?;
        let water_temp = i16::decode(buf_ref)?;
        let steam_temp = i16::decode(buf_ref)?;
        let sensor = u16::decode(buf_ref)?;
        let analog = u16::decode(buf_ref)?;
        let ctrl_flag = u16::decode(buf_ref)?;
        Some(Self { version, water_temp, steam_temp, sensor, analog, ctrl_flag })
    }
}

#[derive(Serialize)]
struct StatusInfoDescript {
    version: String,
    water_temp: i16,
    steam_temp: i16,
    pearl_checked: bool,
    move_origin: bool,
    stir_top: bool,
    stir_bottom: bool,
    trun_left: bool,
    trun_right: bool,
    clamp_left: bool,
    clamp_right: bool,
    move_alm: bool,
    water_high: bool,
    water_low: bool,
    temp_err: bool,

    analog: u16,

    heat_steam_open: bool,
    heat_water_open: bool,
    v3_open: bool,
    v4_open: bool,
    bucket2_pump: bool,
    bucket1_pump: bool,
    v6_open: bool,
    v7_open: bool,
    v2_open: bool,
    v1_open: bool,
    clamp_valve: bool,
    trun_valve: bool,
    water_pump: bool,
    steam_pump: bool,
    v8_open: bool,
    air_pump: bool,
}

impl StatusInfoDescript {

    pub fn new(status: &Status) -> Self {
        Self {
            version: format!("{:04x}", status.version),
            water_temp: status.water_temp,
            steam_temp: status.steam_temp,
            pearl_checked: status.sensor.is_set(0),
            move_origin: status.sensor.is_set(1),
            stir_top: status.sensor.is_set(2),
            stir_bottom: status.sensor.is_set(3),
            trun_left: status.sensor.is_set(4),
            trun_right: status.sensor.is_set(5),
            clamp_left: status.sensor.is_set(6),
            clamp_right: status.sensor.is_set(7),
            move_alm: status.sensor.is_set(8),
            water_high: status.sensor.is_set(9),
            water_low: status.sensor.is_set(10), 
            temp_err: status.sensor.is_set(11),
            analog: status.analog,

            heat_steam_open: status.ctrl_flag.is_set(0),
            heat_water_open: status.ctrl_flag.is_set(1),
            v3_open: status.ctrl_flag.is_set(2),
            v4_open: status.ctrl_flag.is_set(3),
            bucket2_pump: status.ctrl_flag.is_set(4),
            bucket1_pump: status.ctrl_flag.is_set(5),
            v6_open: status.ctrl_flag.is_set(6),
            v7_open: status.ctrl_flag.is_set(7),
            v2_open: status.ctrl_flag.is_set(8),
            v1_open: status.ctrl_flag.is_set(9),
            clamp_valve: status.ctrl_flag.is_set(10),
            trun_valve: status.ctrl_flag.is_set(11),
            water_pump: status.ctrl_flag.is_set(12),
            steam_pump: status.ctrl_flag.is_set(13),
            v8_open: status.ctrl_flag.is_set(14),
            air_pump: status.ctrl_flag.is_set(15),
        }
    }
}

fn on_status(frame: Frame) -> Result<(), AppErr> {
    let status: Status = frame.parse_cmd()?;
    let status = StatusInfoDescript::new(&status);
    APP.notify_heat(&status);
    Ok(())
}








